<?php
namespace app\modules\developer\models;
use ac\component\tool\Tool;
use app\models\Basic;

use Yii;

class Menu extends Basic
{  
    public static function tableName()
    {
        return '{{%menu}}';
    }

    public function rules()
    {
        return [
            ['name', 'required', 'message' => 'name不能为空', 'on' => 'add'],
            ['name', 'string', 'message' => 'name必须是字符串',
                     'min' => 2, 'tooShort' => 'name最短2位',
                     'max' => 16, 'tooLong' => 'name最长16位'],
            ['icon', 'default', 'value' => ''],
            ['icon', 'string', 'message' => 'icon必须是字符串', 
                     'max' => 32, 'tooLong' => 'icon最长32位'],
            ['parentid', 'default', 'value' => 0, 'on' => 'add'],
            ['parentid', 'integer', 'message' => 'parentid必须为数字，或数字字符串', 
                         'min'=>0, 'tooSmall' => 'parentid最小存储0', 
                         'max'=>65535, 'tooBig' => 'parentid最大存储65535'],
            ['allparentid', 'default', 'value' => '0'],
            ['allparentid', 'string', 'message' => 'allparentid必须是字符串', 
                              'max' => 512, 'tooLong' => 'allparentid最长512位'],
            ['child', 'default', 'value' => 1],
            ['child', 'integer', 'message' => 'child必须为数字，或数字字符串'],
            ['child', 'in', 'range' => array(1, 2), 'message' => 'child值必须在1,2,3中选择'],
            ['allchildid', 'default', 'value' => ''],
            ['allchildid', 'string', 'message' => 'allchildid必须是字符串', 
                             'max' => 512, 'tooLong' => 'allchildid最长512位'],   
            ['apikeyname', 'default', 'value' => ''],
            ['apikeyname', 'string', 'message' => 'apikeyname必须是字符串', 
                           'max' => 64, 'tooLong' => 'apikeyname最长64位'],
            ['m', 'default', 'value' => ''],
            ['m', 'string', 'message' => 'm必须是字符串', 
                  'max' => 32, 'tooLong' => 'm最长32位'],
            ['c', 'default', 'value' => ''],
            ['c', 'string', 'message' => 'c必须是字符串',
                  'min' => 2, 'tooShort' => 'c最短2位',
                  'max' => 32, 'tooLong' => 'c最长32位'],
            ['a', 'default', 'value' => ''],
            ['a', 'string', 'message' => 'a必须是字符串',
                  'min' => 2, 'tooShort' => 'a最短2位',
                  'max' => 32, 'tooLong' => 'a最长32位'],
            ['args', 'default', 'value' => ''],
            ['args', 'string', 'message' => 'args必须是字符串', 
                     'max' => 512, 'tooLong' => 'args最长512位'],
            ['flag', 'default', 'value' => 0],
            ['flag', 'integer', 'message' => 'flag必须为数字，或数字字符串'],
            ['flag', 'in', 'range' => array(0, 1, 2), 'message' => 'flag值必须在1,2中选择'],
            ['child_route', 'default', 'value' => 1],
            ['child_route', 'integer', 'message' => 'child_route必须为数字，或数字字符串'],
            ['child_route', 'in', 'range' => array(1, 2), 'message' => 'child_route值必须在1,2中选择'],
            // ['link', 'default', 'value' => ''],
            ['link', 'string', 'message' => 'link必须是字符串', 
                                'max' => 128, 'tooLong' => 'link最长64位'],
            ['sort', 'integer', 'message' => 'sort必须为数字，或数字字符串', 
                     'min'=>0, 'tooSmall' => 'sort最小存储0', 
                     'max'=>65535, 'tooBig' => 'sort最大存储65535'],
            ['showflag', 'default', 'value' => 2],
            ['showflag', 'integer', 'message' => 'showflag必须为数字，或数字字符串'],
            ['showflag', 'in', 'range' => array(1, 2, 3, 4), 'message' => 'showflag值必须在1,2,3,4中选择'],
            ['display', 'default', 'value' => 1],
            ['display', 'integer', 'message' => 'display必须为数字，或数字字符串'],
            ['display', 'in', 'range' => array(1, 2), 'message' => 'display值必须在1,2中选择'],
            ['sys_args','safe']
        ];
    }


    /*添加菜单*/
    public function addMenu($data)
    {
        // P($data);
        $this->scenario = 'add';
        if(isset($data['Menu']['child_route'])){
            $data['Menu']['child_route'] = Tool::changeBool($data['Menu']['child_route']);
        }
        if(isset($data['Menu']['display'])){
            $data['Menu']['display'] = Tool::changeBool($data['Menu']['display']);
        }
        if($this->load($data) and $this->validate()){
            /*取出父元素的allparentid 为了完善自己的allparentid*/
            if($this->parentid > 0){//非顶级分类的话
                $menu = Menu::find()->select('id, parentid, allparentid, allchildid')
                        ->where('id = :id', [':id' => $data['Menu']['parentid']])->one();
                if(is_null($menu)){
                    $this->addError('parentid', '上级分类不存在');
                    return false;
                }
                $this->allparentid = $menu->allparentid . ',' . $menu->id;
            }

            $transaction = Yii::$app->db->beginTransaction();//事物处理
            $pass = true;
            try{
                /*添加菜单*/
                if($this->save(false)){
                    $id = $this->getPrimaryKey();
                    $this->updateAll(['sort' => $id], 'id = :id', [':id' => $id]);
                }else{
                    $pass = false;
                }

                if($pass){
                    /*循环自身的所有父元素ID，修改父元素的child 和 allchildid*/
                    for($i=0; $i<count($allParentIdArr = explode(',', $this->allparentid)); $i++){
                        if($allParentIdArr[$i]){
                            $menu = self::find()
                                        ->select('id, parentid, allparentid, allchildid')
                                        ->where('id = :id', [':id' => $allParentIdArr[$i]])
                                        ->one();
                            $menu->child = 2;
                            $menu->allchildid = ($menu->allchildid?$menu->allchildid . ',':'') . $id;
                            if(!$menu->save(false)){
                                $pass = false;
                            }
                        }
                    }
                }

                if($pass){
                    $transaction->commit();
                    return $id;
                }
            }catch(\Exception $exception){
                $transaction->rollback();       
                return false;
            };
        }
        return false;
    }

    /*
    修改菜单
    $data   修改的数据
    $id     菜单ID
    $flag   值为setShowflag时 作用是更改显示标识，值为setDisplay时 作用是更改是否显示，为空是修改菜单
    */
    public function modifyMenu($data, $id, $flag = '')
    {
        // P($data);
        if(empty($flag) and (!isset($data['Menu']['name']) or empty($data['Menu']['name']))){
            $this->addError('name', 'name不能为空');
            return false;
        }
        if(isset($data['Menu']['child_route'])){
            $data['Menu']['child_route'] = Tool::changeBool($data['Menu']['child_route']);
        }
        if(isset($data['Menu']['display'])){
            $data['Menu']['display'] = Tool::changeBool($data['Menu']['display']);
        }
        $menu = Menu::find()->where('id = :id', [':id' => $id])->one();//之前的数据
        $oldParentid = $menu->parentid;//保存老的parentid 为了下面比较是否更换了父级
        $oldAllparentid = $menu->allparentid;//保存老的allparentid 为了下面修改老父级的allchildid
        $oldAllchildid = $menu->allchildid;//保存老的allchildid 为了下面比较是否更换了父级
        if(!is_null($menu)){
            if($this->load($data) and $this->validate()){
                if(!empty($this->name) and empty($flag)){
                    $menu->name = $this->name;
                }
                if(!empty($this->icon) and empty($flag)){
                    $menu->icon = $this->icon;
                }
                if((isset($this->parentid) and $this->parentid >= 0) and empty($flag)){
                    $menu->parentid = $this->parentid;
                }
                if(empty($flag)){
                    $menu->apikeyname = $this->apikeyname;
                }
                if(empty($flag)){
                    $menu->m = $this->m;
                }
                if(empty($flag)){
                    $menu->c = $this->c;
                }
                if(empty($flag)){
                    $menu->a = $this->a;
                }
                if(!empty($this->args) and empty($flag)){
                    $menu->args = $this->args;
                }
                if((isset($this->flag) and $this->flag >= 0) and empty($flag)){
                    $menu->flag = $this->flag;
                }
                if(empty($flag)){
                    $menu->child_route = $this->child_route;
                }
                if(isset($this->link) and empty($flag)){
                    $menu->link = $this->link;
                }
                if(!empty($this->showflag) and $flag != 'setDisplay'){
                    $menu->showflag = $this->showflag;
                }
                if(!empty($this->display) and $flag != 'setShowflag'){
                    $menu->display = $this->display;
                }
                // P($menu);


                /*
                如果分类有变化
                需要改动所有之前所有父级allparentid、child、allchildid数据
                还要改动现在的所有父级allparentid、child、allchildid数据
                */

                $transaction = Yii::$app->db->beginTransaction();//事物处理
                $pass = true;
                try{
                    if($menu->parentid != $oldParentid){
                        if($this->parentid > 0){
                            /*现在的父级数据*/
                            $parentMenu = Menu::find()->select('id, parentid, allparentid, allchildid')
                                          ->where('id = :id', [':id' => $data['Menu']['parentid']])->one();

                            /*非顶级分类的话，验证父级parentid是否存在*/
                            if(is_null($parentMenu)){
                                $this->addError('parentid', '上级分类不存在');
                                return false;
                            }

                            $menu->allparentid = $parentMenu->allparentid . ',' . $this->parentid;//整理自身的allparentid

                            /*判断是否选择是自己和子分类*/
                            if(($this->parentid == $menu->id) or 
                                (in_array($this->parentid, explode(',', $menu->allchildid)))){
                                $this->addError('parentid', '不能选择自身和子级');
                                return false;
                            }
                        }else{
                            $menu->allparentid = '0';//整理自身的allparentid
                        }
                                
                        if(!$menu->save(false)){//保存自身数据
                            $pass = false;
                        }

                        /*
                        修改之前所有父元素的allchildid
                        其实就是去掉自己的id 和自己子元素的id，同时看看下面还有没有子元素，如果没有的话，child字段改成1
                        */
                        if($pass){
                            for($i=0; $i<count($allParentIdArr = explode(',', $oldAllparentid)); $i++){
                                if($allParentIdArr[$i]){
                                    $tmpMenu = self::find()->select('id, allparentid, child, allchildid')
                                               ->where('id = :id', [':id' => $allParentIdArr[$i]])->one();
                                    $tmpArr = explode(',', $tmpMenu->allchildid);
                                    foreach ($tmpArr as $k => $v){
                                        if (($v == $menu->id) or (in_array($v, explode(',', $menu->allchildid)))){
                                            unset($tmpArr[$k]);
                                        }
                                    }
                                    if(count($tmpArr)){
                                        $tmpMenu->child = 2;
                                    }else{
                                        $tmpMenu->child = 1;
                                    }
                                    $tmpMenu->allchildid = implode(',', $tmpArr);
                                    if(!$tmpMenu->save(false)){
                                        $pass = false;
                                    }
                                }
                            }
                        }

                        /*
                        修改现在所有父元素的allchildid
                        就是在所有父级 添加自身的id 和子级的id
                        */
                        if($pass and $menu->allparentid != '0'){
                            for($i=0; $i<count($allParentIdArr = explode(',', $menu->allparentid)); $i++){
                                if($allParentIdArr[$i]){
                                    $tmpMenu = self::find()
                                               ->select('id, allparentid, child, allchildid')
                                               ->where('id = :id', [':id' => $allParentIdArr[$i]])->one();
                                    $tmpMenu->child = 2;
                                    if($menu->allchildid){
                                        $tmpMenu->allchildid = ($tmpMenu->allchildid?$tmpMenu->allchildid . ',':'') . $menu->id . ',' . $menu->allchildid;
                                    }else{
                                        $tmpMenu->allchildid = ($tmpMenu->allchildid?$tmpMenu->allchildid . ',':'') . $menu->id;
                                    }
                                    if(!$tmpMenu->save(false)){
                                        $pass = false;
                                    }
                                }
                            }
                        }


                        /*修改自身所有子元素的allparentid*/
                        if($pass){
                            for($i=0; $i<count($allChildIdArr = explode(',', $menu->allchildid)); $i++){
                                if($allChildIdArr[$i]){
                                    $childMenu = self::find()
                                                ->select('id, parentid, allparentid, child, allchildid')
                                                ->where('id = :id', [':id' => $allChildIdArr[$i]])->one();
                                    $parentMenu = self::find()
                                                  ->select('id, allparentid, child, allchildid')
                                                  ->where('id = :id', [':id' => $childMenu['parentid']])->one();
                                    $childMenu->allparentid = $parentMenu->allparentid . ',' . $parentMenu->id;
                                    $childMenu->save(false);
                                }
                            }
                        }

                        
                    }else{
                        if(!$menu->save(false)){//保存自身数据
                            $pass = false;
                        }
                    }

                    if($pass){
                        $transaction->commit();
                        return true;
                    }
                }catch(\Exception $exception){
                    $transaction->rollback();       
                    return false;
                };
                
            }
        };
        return false;
    }

    /*删除菜单*/
    public function deleteMenu($id)
    {
        $menu = Menu::find()->where('id = :id', [':id' => $id])->one();
        if(is_null($menu)){
            return 10013;
        };
        if($menu->sys_args == 2){//系统参数，不能删除
            return 10004;
        };
        $transaction = Yii::$app->db->beginTransaction();//事物处理
        $pass = true;
        try{
            /*删除ID对应的数据 和 所有子级*/
            if(!$this->deleteAll('id = :id or FIND_IN_SET(:id, allparentid)', [':id' => $id])){
                $pass = false;
            };

            if($pass){
                /*所有父级的 allchildid 去掉已经删除的id*/
                for($i=0; $i<count($allParentIdArr = explode(',', $menu->allparentid)); $i++){
                    if($allParentIdArr[$i]){
                        $tmpMenu = self::find()->select('id, allparentid, child, allchildid')
                                   ->where('id = :id', [':id' => $allParentIdArr[$i]])->one();
                        $tmpArr = explode(',', $tmpMenu->allchildid);
                        foreach ($tmpArr as $k => $v){
                            if (($v == $menu->id) or (in_array($v, explode(',', $menu->allchildid)))){
                                unset($tmpArr[$k]);
                            }
                        }
                        if(count($tmpArr)){
                            $tmpMenu->child = 2;
                        }else{
                            $tmpMenu->child = 1;
                        }
                        $tmpMenu->allchildid = implode(',', $tmpArr);
                        if(!$tmpMenu->save(false)){
                            $pass = false;
                        }
                    }
                }
            }

            /*删除所有对应的VUE路由*/
            if($pass){
                $vueRouter = new VueRouter;
                if(empty($menu->allchildid)){
                    $vueRouter->deleteAll('menuid = :id', [':id' => $id]);
                }else{
                    $vueRouter->deleteAll('menuid = :id or menuid in (' . $menu->allchildid . ')', [':id' => $id]);
                }
            }


            if($pass){
                $transaction->commit();
                return true;
            }
        }catch(\Exception $exception){
            $transaction->rollback();       
            return 10013;
        };
    }

    /*
    取出树形分类
    $model      带有where参数的搜索模型对象
    $flag       ele的时候，取setEleTree()方法
    */
    public static function getTreeList($model, $flag = '', $parentid = 0)
    {
        $menuList = $model->select(['id', '{{%menu}}.name', '{{%menu}}.icon', 'parentid', 'apikeyname', 'm', 'c', 'a', 'args', 'flag', 'child_route', 'link', 'showflag', '{{%menu}}.display'])
                    ->joinWith('vueRouter')
                    ->orderBy(['{{%menu}}.sort' => SORT_ASC])->asArray()->all();

        // P($menuList);
        if($flag == 'ele'){
            $menuList = self::setEleTree($menuList, $parentid);
        }else{
            $menuList = self::setTree($menuList, $parentid);
        }
        return $menuList;
    }
    /*
    递归函数
    返回一个 商品分类 树列表
    $arr        需要处理的数组
    $parentid   父ID
    */
    private static function setTree($arr, $parentid=0)
    {
        static $list = array();
        static $level = 0;//层级
        $level++;

        for($i=0; $i<count($arr); $i++){
            $arr[$i]["level"] = $level;
            $hasTotal = self::getHasNumById($arr, $arr[$i]["id"]);//此ID下有多少条数据(不包含隐藏的菜单)
            $endTotal = self::getEndNumById($arr, $arr[$i]["id"]);//此ID下有多少条数据(包含隐藏的菜单)
            if($arr[$i]["parentid"] == $parentid){
                if($hasTotal){//如果下面有子菜单
                    $arr[$i]["has"] = true;
                }else{
                    $arr[$i]["has"] = false;
                }
                if($endTotal){//如果下面有同级菜单
                    $arr[$i]["end"] = true;
                }else{
                    $arr[$i]["end"] = false;
                }
                array_push($list, $arr[$i]);
                self::setTree($arr, $arr[$i]["id"]);
            }
        }
        $level--;
        return $list;
    }
    /*
    为递归函数服务
    查看父id为 $parentid 的 结果有多少个(不包含隐藏的菜单)
    $arr        匹配的数组
    $parentid   匹配的父ID
    */
    private static function getHasNumById($arr, $parentid)
    {
        $num = 0;
        foreach($arr as $k => $v){
            if(($v["parentid"] == $parentid) && $v["display"]){
                $num++;
            }
        }
        return $num;
    }
    /*
    为递归函数服务
    查看父id为 $parentid 的 结果有多少个(不包含隐藏的菜单)
    $arr        匹配的数组
    $parentid   匹配的父ID
    */
    private static function getEndNumById($arr, $parentid)
    {
        $num = 0;
        foreach($arr as $k => $v){
            if(($v["parentid"] == $parentid)){
                $num++;
            }
        }
        return $num;
    }

    //------------------element TREE(因为目录结构不一样，element TREE子菜单是children包含的)-----------------
    /*
    递归函数
    返回一个 商品分类 树列表
    $list           需要处理的原始数据
    $parentid       父ID
    */
    private static function setEleTree($list, $parentid  = 0)
    {
        $newList = array();
        $j = 0;

        for($i=0; $i<count($list); $i++){
            if($list[$i]["parentid"] == $parentid){
                switch($list[$i]['flag']){
                    case 1:
                        $list[$i]['flag'] = 'hot';
                        break;
                    case 2:
                        $list[$i]['flag'] = 'new';
                        break;
                    default:
                        $list[$i]['flag'] = '';
                };
                if($list[$i]["child_route"] == 1){
                    $list[$i]["child_route"] = false;
                }else{
                    $list[$i]["child_route"] = true;
                }
                if($list[$i]["display"] == 1){
                    $list[$i]["display"] = false;
                }else{
                    $list[$i]["display"] = true;
                }
                $list[$i]['label'] = array(
                    'name' => $list[$i]['name'],
                    'flag' => $list[$i]['flag']
                );
                unset( $list[$i]['name']);
                array_push($newList, $list[$i]);
                $newList[$j]['children'] = self::setEleTree($list, $list[$i]["id"]);
                $j++;
            }
        }
        return $newList;
    }
    //------------------element TREE(因为目录结构不一样，element TREE子菜单是children包含的)-----------------


    /*关联查询 VUE路由*/
    public function getVueRouter()
    {
        $router = $this->hasOne(VueRouter::className(), ['menuid' => 'id']);
        return $router;
    }

    
}